using Microsoft.EntityFrameworkCore;
using Thinker.SignChannel.Books;
using Thinker.SignChannel.Entities;
using Thinker.SignChannel.People;
using Thinker.SignChannel.Times;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.BlobStoring.Database.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.Modeling;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.OpenIddict.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using static Thinker.SignChannel.SignChannelConsts;

namespace Thinker.SignChannel.EntityFrameworkCore;

[ReplaceDbContext(typeof(IIdentityDbContext))]
[ReplaceDbContext(typeof(ITenantManagementDbContext))]
[ConnectionStringName("Default")]
public class SignChannelDbContext :
    AbpDbContext<SignChannelDbContext>,
    ITenantManagementDbContext,
    IIdentityDbContext
{
    public SignChannelDbContext(DbContextOptions<SignChannelDbContext> options)
        : base(options)
    {
    }
    /* Add DbSet properties for your Aggregate Roots / Entities here. */

    public DbSet<Book> Books { get; set; }
    public DbSet<Person> People { get; set; }
    public DbSet<Time> Times { get; set; }
    public DbSet<PersonTime> PersonTimes { get; set; }
    public DbSet<Record> Records { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        /* Include modules to your migration db context */

        builder.ConfigurePermissionManagement();
        builder.ConfigureSettingManagement();
        builder.ConfigureBackgroundJobs();
        builder.ConfigureAuditLogging();
        builder.ConfigureFeatureManagement();
        builder.ConfigureIdentity();
        builder.ConfigureOpenIddict();
        builder.ConfigureTenantManagement();
        builder.ConfigureBlobStoring();

        builder.Entity<Book>(b =>
        {
            b.ToTable(DbTablePrefix + "Books",
                DbSchema);
            b.ConfigureByConvention(); //auto configure for the base class props
            b.Property(x => x.Name).IsRequired().HasMaxLength(128);
        });

        /* Configure your own tables/entities inside here */

        builder.Entity<Person>(b =>
        {
            b.ToTable(DbTablePrefix + "People", DbSchema);
            b.ConfigureByConvention();

            b.Property(x => x.PersonName).IsRequired().HasMaxLength(PersonConsts.MaxNameLength);
            b.Property(x => x.IdNumber).IsRequired().HasMaxLength(PersonConsts.MaxIdNumberLength);
            b.Property(x => x.Sex).IsRequired(false).HasMaxLength(PersonConsts.MaxSexLength);
            b.Property(x => x.PersonCode).IsRequired(false)
                .HasMaxLength(PersonConsts.MaxPersonCodeLength);
            b.Property(x => x.PersonType).IsRequired(false)
                .HasMaxLength(PersonConsts.MaxPersonTypeLength);

            b.HasIndex(x => x.IdNumber);
        });

        builder.Entity<Time>(b =>
        {
            b.ToTable(DbTablePrefix + "Times", DbSchema);
            b.ConfigureByConvention();

            b.Property(x => x.Period).IsRequired().HasMaxLength(TimeConsts.MaxPeriodLength);


            b.HasIndex(x => new { x.SignDate, x.Period, x.Direction });
        });

        builder.Entity<PersonTime>(b =>
        {
            b.ToTable(DbTablePrefix + "PersonTimes", DbSchema);
            b.ConfigureByConvention();

            b.HasOne<Person>().WithMany().IsRequired().HasForeignKey(e => e.PersonId);
            b.HasOne<Time>().WithMany().IsRequired().HasForeignKey(e => e.TimeId);

            b.HasIndex(x => new { x.PersonId, x.TimeId });
        });

        builder.Entity<Record>(b =>
        {
            b.ToTable(DbTablePrefix + "Records", DbSchema);
            b.ConfigureByConvention();

            b.HasOne<Person>().WithMany().IsRequired(false).HasForeignKey(e => e.PersonId);
            b.HasOne<Time>().WithMany().IsRequired(false).HasForeignKey(e => e.TimeId);

            b.HasIndex(x => new { x.PersonId, x.TimeId });
        });
    }

    #region Entities from the modules

    /* Notice: We only implemented IIdentityProDbContext
     * and replaced them for this DbContext. This allows you to perform JOIN
     * queries for the entities of these modules over the repositories easily. You
     * typically don't need that for other modules. But, if you need, you can
     * implement the DbContext interface of the needed module and use ReplaceDbContext
     * attribute just like IIdentityProDbContext .
     *
     * More info: Replacing a DbContext of a module ensures that the related module
     * uses this DbContext on runtime. Otherwise, it will use its own DbContext class.
     */

    // Identity
    public DbSet<IdentityUser> Users { get; set; }
    public DbSet<IdentityRole> Roles { get; set; }
    public DbSet<IdentityClaimType> ClaimTypes { get; set; }
    public DbSet<OrganizationUnit> OrganizationUnits { get; set; }
    public DbSet<IdentitySecurityLog> SecurityLogs { get; set; }
    public DbSet<IdentityLinkUser> LinkUsers { get; set; }
    public DbSet<IdentityUserDelegation> UserDelegations { get; set; }
    public DbSet<IdentitySession> Sessions { get; set; }

    // Tenant Management
    public DbSet<Tenant> Tenants { get; set; }
    public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }

    #endregion
}